package gredis

import (
	"context"
	"time"

	"github.com/redis/go-redis/v9"
)

// type Nil = redi
const Nil = redis.Nil

// Ping 测试连接
func (c *Client) Ping(ctx context.Context) (string, error) {
	return c.rdb.Ping(ctx).Result()
}

// Get 获取key的值 (key不存在时`err`返回`gredis.Nil“)
func (c *Client) Get(ctx context.Context, key string) (string, error) {
	return c.rdb.Get(ctx, key).Result()
}

// Set 设置key的值
func (c *Client) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error {
	return c.rdb.Set(ctx, key, value, expiration).Err()
}

// Del 删除key
func (c *Client) Del(ctx context.Context, keys ...string) (int64, error) {
	return c.rdb.Del(ctx, keys...).Result()
}

// Exists 检查key是否存在
func (c *Client) Exists(ctx context.Context, keys ...string) (int64, error) {
	return c.rdb.Exists(ctx, keys...).Result()
}

// Expire 设置过期时间
func (c *Client) Expire(ctx context.Context, key string, expiration time.Duration) (bool, error) {
	return c.rdb.Expire(ctx, key, expiration).Result()
}

// TTL 获取key的剩余过期时间
func (c *Client) TTL(ctx context.Context, key string) (time.Duration, error) {
	return c.rdb.TTL(ctx, key).Result()
}

// Incr 自增
func (c *Client) Incr(ctx context.Context, key string) (int64, error) {
	return c.rdb.Incr(ctx, key).Result()
}

// Decr 自减
func (c *Client) Decr(ctx context.Context, key string) (int64, error) {
	return c.rdb.Decr(ctx, key).Result()
}

// HSet 哈希设置
func (c *Client) HSet(ctx context.Context, key string, values ...interface{}) (int64, error) {
	return c.rdb.HSet(ctx, key, values...).Result()
}

// HGet 哈希获取
func (c *Client) HGet(ctx context.Context, key, field string) (string, error) {
	return c.rdb.HGet(ctx, key, field).Result()
}

// HGetAll 获取所有哈希字段
func (c *Client) HGetAll(ctx context.Context, key string) (map[string]string, error) {
	return c.rdb.HGetAll(ctx, key).Result()
}

// LPush 列表左推入
func (c *Client) LPush(ctx context.Context, key string, values ...interface{}) (int64, error) {
	return c.rdb.LPush(ctx, key, values...).Result()
}

// RPop 列表右弹出
func (c *Client) RPop(ctx context.Context, key string) (string, error) {
	return c.rdb.RPop(ctx, key).Result()
}

// SAdd 集合添加
func (c *Client) SAdd(ctx context.Context, key string, members ...interface{}) (int64, error) {
	return c.rdb.SAdd(ctx, key, members...).Result()
}

// SMembers 获取集合所有成员
func (c *Client) SMembers(ctx context.Context, key string) ([]string, error) {
	return c.rdb.SMembers(ctx, key).Result()
}

// ZAdd 有序集合添加
func (c *Client) ZAdd(ctx context.Context, key string, members ...redis.Z) (int64, error) {
	return c.rdb.ZAdd(ctx, key, members...).Result()
}

// ZRange 有序集合范围查询
func (c *Client) ZRange(ctx context.Context, key string, start, stop int64) ([]string, error) {
	return c.rdb.ZRange(ctx, key, start, stop).Result()
}

// 普通锁
func (c *Client) Lock(ctx context.Context, key string, lockId string, expire time.Duration) (bool, error) {
	return c.rdb.SetNX(ctx, key, lockId, expire).Result()
}

// 释放锁(只有持有者才可以释放), 通常与`Lock`方法成对使用
func (c *Client) UnLock(ctx context.Context, key string, lockId string) (bool, error) {
	script := `
	if redis.call("GET", KEYS[1]) == ARGV[1] then
		return redis.call("DEL", KEYS[1])
	else
		return 0
	end`

	res, e := c.rdb.Eval(ctx, script, []string{key}, lockId).Result()
	if e != nil {
		return false, e
	}

	return res == 1, nil
}

// 续期锁(适合单点/没有故障转移机制)
//
//	@param 	ctx				上下文
//	@param 	key				Key
//	@param 	lockId			持有者ID
//	@param 	expire			相对过期时间
//
//	@return
//		成功加锁/续期返回true, 失败返回false
func (c *Client) RenewableLock(ctx context.Context, key string, lockId string, expire time.Duration) (bool, error) {
	script := `
	if redis.call("EXISTS", KEYS[1]) == 0 then
		return redis.call("SET", KEYS[1], ARGV[1], "PX", ARGV[2], "NX")
	elseif redis.call("GET", KEYS[1]) == ARGV[1] then
		return redis.call("PEXPIRE", KEYS[1], ARGV[2])
	else
		return 0
	end`

	res, e := c.rdb.Eval(ctx, script, []string{key}, lockId, expire.Milliseconds()).Result()
	if e != nil {
		return false, e
	}

	return res == "OK" || res == 1, nil
}
